package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.bean.Category;
import com.itheima.bean.Dish;
import com.itheima.bean.DishFlavor;
import com.itheima.common.PageParam;
import com.itheima.dao.DishDao;
import com.itheima.dto.DishDto;
import com.itheima.service.CategoryService;
import com.itheima.service.DishFlavorService;
import com.itheima.service.DishService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Transactional
@Service
public class DishServiceImpl implements DishService {

    @Autowired
    private DishDao dishDao;

    @Autowired
    private DishFlavorService dishFlavorService;

    @Lazy
    @Autowired
    private CategoryService categoryService;


    /**
     * 根据分类的id查询菜品数据
     *
     * @param categoryId
     * @return
     */
    @Override
    public List<DishDto> findByCategoryId(Long categoryId , Integer status) {

        //1. 构建条件对象
        LambdaQueryWrapper<Dish> lqw = new LambdaQueryWrapper<>();

        //2. 封装条件
        lqw.eq(Dish::getCategoryId , categoryId);
        lqw.eq(status != null , Dish::getStatus , status);

        //3. 执行查询
        List<Dish> dishList = dishDao.selectList(lqw);


        //4. 为了迎合移动端的需求，这里不能直接返回List<Dish> ，需要返回List<DishDto>
        //  DishDto 里面出了包装Dish本身的数据之外，还可以包装口味数据
        return dishList.stream().map(dish->{
            //4.1 构建一个DishDto
            DishDto dishDto = new DishDto();

            //4.2 封装dish本身的数据
            BeanUtils.copyProperties(dish , dishDto);
            //4.3 封装口味数据
            List<DishFlavor> flavorList = dishFlavorService.findByDishId(dish.getId());

            dishDto.setFlavors(flavorList);

            return dishDto;
        }).collect(Collectors.toList());
    }

    /**
     * 添加菜品
     *   1. 添加菜品和其他的添加操作不一样，因为它要往两张表里面添加数据： dish表 和 dish_flavor表
     *      1.1. 先添加菜品表，这样就可以得到这道菜在表里面的主键id值。
     *          a. 在mybatisplus里面，当添加成功之后，主键id会自动设置到主键属性上。
     *
     *      1.2. 再添加口味表。
     *          a. 在添加口味表之前，得先设置口味数据属于哪一道菜，其实就是设置菜品的id值。
     *
     *
     * @param dishDto
     * @return
     */
    @Override
    public int add(DishDto dishDto) {
        //1. 往菜品表添加数据
        int row = dishDao.insert(dishDto);

        //2. 往口味表添加数据
        if(row > 0){
            //2.1 获取口味数据
            List<DishFlavor> flavorList = dishDto.getFlavors();

            //2.2 遍历每一个口味数据
            int row2 = 0;

            if(flavorList != null && flavorList.size() > 0){
                for (DishFlavor dishFlavor : flavorList) {

                    //2.3 设置菜品id
                    dishFlavor.setDishId(dishDto.getId());

                    //2.4 添加口味
                    row2 += dishFlavorService.add(dishFlavor);
                }

                //如果口味表添加的影响行数和集合本身的元素个数是一样的，那么就认为添加成功了，否则失败。！
                return row2 == flavorList.size() ? 1 : 0 ;
            }
        }

        return row;
    }



    /**
     * 菜品分页
     *
     * @param pageParam
     * @return
     */
    @Override
    public  IPage<DishDto> findPage(PageParam pageParam) {

        //1. 构建分页对象
        IPage<Dish> p = new Page<>(pageParam.getPage() , pageParam.getPageSize());

        //2. 构建条件对象
        LambdaQueryWrapper<Dish> lqw = new LambdaQueryWrapper<>();

        //3. 追加条件
        lqw.like(pageParam.getName() != null, Dish::getName , pageParam.getName());

        //4. 执行查询:: 得到菜品的数据，但是菜品的数据里面没有分类的数据。
        IPage<Dish> dishIPage = dishDao.selectPage(p, lqw);

        //5. 遍历每一条菜品数据，拿着每一条菜品数据的分类id去查询分类的对象，然后回来和每一条菜品数据
        //    封装成一个DishDto
        List<DishDto> dishDtoList = dishIPage.getRecords().stream().map(dish ->{

            //1. 拿着dish的分类id去查询分类表，得到分类的对象。
            Category category = categoryService.findById(dish.getCategoryId());

            //2. 想方设法把遍历出来的dish对象和category的名称，组合成一个新的对象DishDto
            DishDto dishDto = new DishDto();

            //2.1 设置dishDto里面的分类数据
            dishDto.setCategoryName(category.getName());

            //2.2 设置dishDto里面的菜品数据
            // BeanUtils.copyProperties： 用来拷贝数据的，拷贝同名属性 参数一：源对象，参数二：目标对象
            BeanUtils.copyProperties(dish , dishDto);

            //2.3 设置dishDto里面的口味数据
            //2.3.1 先根据菜品的id去查询菜品口味表，得到该菜品的口味数据
            List<DishFlavor> flavorList = dishFlavorService.findByDishId(dish.getId());

            //2.3.2 添加到DishDto里面去。
            dishDto.setFlavors(flavorList);


            //3. 返回dishDto
            return dishDto;
        }).collect(Collectors.toList());


        //6. 构建一个新的IPage<DishDto>对象
        IPage<DishDto> dishDtoIPage = new Page<>();

        //7. 设置数据，页面只需要两个数据就能够显示数据： records 和 total
        dishDtoIPage.setTotal(dishIPage.getTotal());
        dishDtoIPage.setRecords(dishDtoList);

        //8. 返回dishdtoIpage
        return dishDtoIPage;
    }

    /**
     * 更新菜品
     *  1. 更新菜品需要往两张表里面更新数据：  dish表  和 dish_flavor表
     *      1.1 更新菜品表，其实很简单，根据菜品的id来更新数据即可。
     *      1.2 更新口味表，却不是这么简单！
     *          1.2.1 更新口味因为有很多种选择，所以不能按照以往的更新来看待：
     *              a. 可以增加一种新的口味设置
     *              b. 可以删除一种旧的口味设置
     *              c. 可以修改一种旧的口味数据
     *          1.2.2 干脆这么做： 先把原来的口味数据删除了，再添加页面传递过来的口味数据
     *          1.2.3 只要保证数据是对的，即可！
     * @param dishDto
     * @return
     */
    @Override
    public int update(DishDto dishDto) {

        //1. 先更新菜品数据
        int row1 = dishDao.updateById(dishDto);

        if(row1 >0 ){

            //2. 再更新口味数据
            //2.1 先根据菜品的id，去把口味表里面的口味数据删除掉
            int row2 = dishFlavorService.delete(dishDto.getId());


            //2.2 再把口味数据添加到口味表里面
            List<DishFlavor> flavorList = dishDto.getFlavors();

            if(flavorList != null && flavorList.size() > 0){

                int row3  = 0 ;

                //2.2.1 遍历每一个口味数据
                for (DishFlavor dishFlavor : flavorList) {

                    //2.2.2 设置口味数据属于哪一个菜品
                    dishFlavor.setDishId(dishDto.getId());

                    //2.2.3 添加口味数据到口味表
                    row3 += dishFlavorService.add(dishFlavor);
                }

                //如果添加口味的数据影响的行数，等价于页面传递过来的口味条数，那么就认为成功了，返回1， 否则返回0.
                return row3 == flavorList.size() ? 1 :  0 ;

            }
        }
        return row1;
    }

}
